/*
 * Copyright (C) 2008 Universidade Federal de Campina Grande
 *  
 * This file is part of OurGrid. 
 *
 * OurGrid is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free 
 * Software Foundation, either version 3 of the License, or (at your option) 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details. 
 * 
 * You should have received a copy of the GNU Lesser General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package org.ourgrid.worker.communication.receiver;

import java.security.cert.X509Certificate;
import java.util.List;

import org.ourgrid.common.interfaces.AccountingAggregator;
import org.ourgrid.common.interfaces.WorkerSpecListener;
import org.ourgrid.common.interfaces.management.WorkerManagement;
import org.ourgrid.common.interfaces.management.WorkerManagementClient;
import org.ourgrid.common.internal.OurGridRequestControl;
import org.ourgrid.reqtrace.Req;
import org.ourgrid.worker.WorkerConfiguration;
import org.ourgrid.worker.WorkerConstants;
import org.ourgrid.worker.request.SetPeerRequestTO;
import org.ourgrid.worker.request.StopWorkingRequestTO;
import org.ourgrid.worker.request.WorkForBrokerRequestTO;
import org.ourgrid.worker.request.WorkForPeerRequestTO;

import br.edu.ufcg.lsd.commune.api.FailureNotification;
import br.edu.ufcg.lsd.commune.api.InvokeOnDeploy;
import br.edu.ufcg.lsd.commune.api.MonitoredBy;
import br.edu.ufcg.lsd.commune.api.RecoveryNotification;
import br.edu.ufcg.lsd.commune.container.servicemanager.ServiceManager;
import br.edu.ufcg.lsd.commune.identification.DeploymentID;

/**
 * WorkerManagementReceiver, called by the management peer.
 *  Its callback is WorkerManagementClient.
 * @see org.ourgrid.common.interfaces.management.WorkerManagement
 */
@Req("REQ004")
public class WorkerManagementReceiver implements WorkerManagement {
	
	private static final long serialVersionUID = 1L;

	private ServiceManager serviceManager;

	@Req("REQ090")
	@InvokeOnDeploy
	public void init(ServiceManager serviceManager) {
		this.serviceManager = serviceManager;
	}
	
	/**
	 * @return the serviceManager
	 */
	protected ServiceManager getServiceManager() {
		return serviceManager;
	}
	
	@Req({"REQ006", "REQ090"})
	public void setPeer(@MonitoredBy(WorkerConstants.LOCAL_WORKER_MANAGEMENT) WorkerManagementClient workerManagementClient, 
			@MonitoredBy(WorkerConstants.LOCAL_WORKER_MANAGEMENT) AccountingAggregator accounting,
			@MonitoredBy(WorkerConstants.LOCAL_WORKER_MANAGEMENT) WorkerSpecListener workerSpecListener) {
		
		DeploymentID stubDeploymentID = getServiceManager().getStubDeploymentID(workerManagementClient);
		String peerID = stubDeploymentID.toString();
		String senderPublicKey = getServiceManager().getSenderPublicKey();
		String accountingAggregatorAddress = getServiceManager().getStubDeploymentID(accounting).toString();
		
		SetPeerRequestTO to = new SetPeerRequestTO();
		to.setPeerDID(peerID);
		to.setPeerAddress(stubDeploymentID.getServiceID().toString());
		to.setPeerPublicKey(getPeerPubKey());
		to.setSenderPublicKey(senderPublicKey);
		to.setWorkerSpecListenerAddress(getServiceManager().getStubDeploymentID(workerSpecListener).toString());
		to.setIdlenessDetectorOn(isIdlenessDetectorOn());
		to.setWorkerSpecReportPropOn(isWorkerSpecReportPropOn());
		to.setWorkerSpecReportTime(getServiceManager().getContainerContext().parseLongProperty(
				WorkerConfiguration.PROP_WORKER_SPEC_REPORT_TIME) * 1000);
		to.setAccountingAggregatorAddress(accountingAggregatorAddress);
		
		OurGridRequestControl.getInstance().execute(to, getServiceManager());
	}
	
	@FailureNotification
	public void doNotifyFailure(WorkerManagementClient monitorable, DeploymentID monitorableID) {
		WorkerManagementClientFailureReceiver.getInstance().doNotifyFailure(serviceManager, monitorable, monitorableID);
	}
	
	@RecoveryNotification
	public void doNotifyRecovery(WorkerManagementClient monitorable) {
		WorkerManagementClientFailureReceiver.getInstance().doNotifyRecovery(serviceManager, monitorable);
	}
	
	private boolean isIdlenessDetectorOn() {
		String propIdlenessDetector = 
			(String) getServiceManager().getContainerContext().getProperty(WorkerConfiguration.PROP_IDLENESS_DETECTOR);
		
		return (propIdlenessDetector == null) ? 
			false : !propIdlenessDetector.equals(WorkerConfiguration.DEF_PROP_IDLENESS_DETECTOR);
	}
	
	private boolean isWorkerSpecReportPropOn() {
		String propWorkerSpecReport = 
			(String) getServiceManager().getContainerContext().getProperty(WorkerConfiguration.PROP_WORKER_SPEC_REPORT);
		
		return (propWorkerSpecReport == null) ? false: 
			!propWorkerSpecReport.equals(WorkerConfiguration.DEF_WORKER_SPEC_REPORT);
	}

	@Req({"REQ006", "REQ092"})
	public void workForBroker(DeploymentID brokerID) {
		WorkForBrokerRequestTO to = new WorkForBrokerRequestTO();
		to.setSenderPublicKey(getServiceManager().getSenderPublicKey());
		to.setPeerPublicKey(getPeerPubKey());
		to.setBrokerID(brokerID.toString());
		to.setBrokerPublicKey(brokerID.getPublicKey());
		
		OurGridRequestControl.getInstance().execute(to, getServiceManager());
	}
	
	public void workForPeer(String remotePeerPublicKey, List<String> usersDN,
			List<X509Certificate> caCertificates) {
		
		WorkForPeerRequestTO to = new WorkForPeerRequestTO();
		to.setSenderPublicKey(getServiceManager().getSenderPublicKey());
		to.setRemotePeerPublicKey(remotePeerPublicKey);
		to.setUsersDN(usersDN);
		to.setCaCertificates(caCertificates);
		to.setPeerPublicKey(getPeerPubKey());
		to.setClientAddress(getServiceManager().getSenderServiceID().toString());

		OurGridRequestControl.getInstance().execute(to, getServiceManager());
	}
	
	@Req("REQ006")
	public void workForPeer(String remotePeerPublicKey) {
		WorkForPeerRequestTO to = new WorkForPeerRequestTO();
		to.setSenderPublicKey(getServiceManager().getSenderPublicKey());
		to.setRemotePeerPublicKey(remotePeerPublicKey);
		to.setPeerPublicKey(getPeerPubKey());
		to.setClientAddress(getServiceManager().getSenderServiceID().toString());

		OurGridRequestControl.getInstance().execute(to, getServiceManager());
	}

	@Req("REQ091")
	public void stopWorking() {
		StopWorkingRequestTO to = new StopWorkingRequestTO();
		to.setPeerPublicKey(getPeerPubKey());
		to.setSenderPublicKey(getServiceManager().getSenderPublicKey());

		OurGridRequestControl.getInstance().execute(to, getServiceManager());
	}
	
	private String getPeerPubKey() {
		return getServiceManager().getContainerContext().getProperty(WorkerConfiguration.PROP_PEER_PUBLIC_KEY);
	}
	
	@RecoveryNotification
	public void accAggregatorIsUp(AccountingAggregator accounting) {}
	
	@FailureNotification
	public void accAggregatorIsDown(AccountingAggregator accounting) {}

	@RecoveryNotification
	public void listenerIsUp(WorkerSpecListener client) {}
	
	@FailureNotification
	public void listenerIsDown(WorkerSpecListener client) {}
}